package com.ibeeking.found.msg.rest.service.impl;

import com.ibeeking.found.common.enums.PublishStatusEnum;
import com.ibeeking.found.common.enums.mp.WxMpSourceTypeEnum;
import com.ibeeking.found.common.utils.UserUtils;
import com.ibeeking.found.msg.rest.service.IMpAutoMessageKeyService;
import com.ibeeking.found.msg.rest.service.IMpAutoMessageService;
import com.ibeeking.found.msg.rest.service.IWxMpSourceService;
import com.ibeeking.found.msg.rest.service.IOpenService;
import com.ibeeking.found.msg.service.common.bo.KeyWordBO;
import com.ibeeking.found.msg.service.common.bo.MpAutoMessageBO;
import com.ibeeking.found.msg.service.common.bo.MpAutoMessageKeyBO;
import com.ibeeking.found.msg.service.common.constants.MessageEventEnum;
import com.ibeeking.found.msg.service.common.dos.MpAutoMessageDO;
import com.ibeeking.found.msg.service.common.dos.MpAutoMessageKeyDO;
import com.ibeeking.found.msg.service.common.param.MpAutoMessageParam;
import com.ibeeking.found.msg.service.common.query.KeyWordQuery;
import com.ibeeking.found.msg.service.common.query.MpMessagePageQuery;
import com.ibeeking.found.msg.service.common.vo.MpAutoMessagePageVO;
import com.ibeeking.found.msg.service.common.vo.MpAutoMessageVO;
import com.ibeeking.found.msg.service.common.vo.WxMpSourceDetailPageVO;
import com.ibeeking.found.msg.service.common.vo.WxMpSourceVO;
import com.ibeeking.found.msg.service.mapper.MpAutoMessageKeyMapper;
import com.ibeeking.found.msg.service.mapper.MpAutoMessageMapper;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.log.utils.LogUtils;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.data.StringUtils;
import com.ibeeking.nematos.utils.id.IdGenerator;
import com.ibeeking.nematos.utils.json.JsonUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import lombok.SneakyThrows;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpCurrentAutoReplyInfo;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName MpAutoMessageServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2021-02-07 11:30
 **/
@Service
public class MpAutoMessageServiceImpl implements IMpAutoMessageService {

    @Resource
    private IOpenService wxOpenServiceImpl;

    @Resource
    private MpAutoMessageMapper mpAutoMessageMapper;

    @Resource
    private MpAutoMessageKeyMapper mpAutoMessageKeyMapper;

    @Resource
    private IWxMpSourceService mpSourceServiceImpl;
    @Resource
    private IMpAutoMessageKeyService mpAutoMessageKeyServiceImpl;

    @Override
    public Page<MpAutoMessagePageVO> pageList(MpMessagePageQuery query) {
        LambdaQueryWrapper<MpAutoMessageDO> queryWrapper = new LambdaQueryWrapper<>(MpAutoMessageDO.class)
                .eq(MpAutoMessageDO::getAppId, query.getAppId())
                .eq(MpAutoMessageDO::getAutoType, query.getEventType())
                .eq(StringUtils.isNotBlank(query.getSourceType()), MpAutoMessageDO::getSourceType, query.getSourceType())
                .eq(null != query.getPublishStatus(), MpAutoMessageDO::getPublishStatus, query.getPublishStatus())
                .like(StringUtils.isNotBlank(query.getRuleName()), MpAutoMessageDO::getName, query.getRuleName())
                .orderByDesc(MpAutoMessageDO::getCreateTime);
        Page<MpAutoMessageDO> queryPage = mpAutoMessageMapper.selectPage(new Page<>(query.getPageNum(), query.getPageSize()), queryWrapper);
        Page<MpAutoMessagePageVO> result = BeanUtil.convertBean(queryPage, Page.class);
        List<MpAutoMessageDO> records = queryPage.getRecords();
        if (!Collections3.isEmpty(records)) {
            if (MessageEventEnum.KEY.getEventType().equals(query.getEventType())) {
                List<MpAutoMessagePageVO> vos = new ArrayList<>();
                records.stream().forEach(mpAutoMessageDO -> {
                    MpAutoMessagePageVO mpAutoMessagePageVO = new MpAutoMessagePageVO();
                    mpAutoMessagePageVO.setId(mpAutoMessageDO.getId());
                    mpAutoMessagePageVO.setAppId(mpAutoMessageDO.getAppId());
                    mpAutoMessagePageVO.setEventType(mpAutoMessageDO.getAutoType());
                    mpAutoMessagePageVO.setRuleName(mpAutoMessageDO.getName());
                    mpAutoMessagePageVO.setPublishStatus(mpAutoMessageDO.getPublishStatus());
                    MpAutoMessagePageVO.Message message = new MpAutoMessagePageVO.Message();
                    message.setSourceType(mpAutoMessageDO.getSourceType());
                    mpAutoMessagePageVO.setMessage(message);
                    vos.add(mpAutoMessagePageVO);
                });
                result.setRecords(vos);
            } else {
                MpAutoMessageDO mpAutoMessageDO = records.get(0);
                MpAutoMessagePageVO mpAutoMessagePageVO = new MpAutoMessagePageVO();
                mpAutoMessagePageVO.setId(mpAutoMessageDO.getId());
                mpAutoMessagePageVO.setAppId(mpAutoMessageDO.getAppId());
                mpAutoMessagePageVO.setEventType(mpAutoMessageDO.getAutoType());
                mpAutoMessagePageVO.setRuleName(mpAutoMessageDO.getName());
                mpAutoMessagePageVO.setPublishStatus(mpAutoMessageDO.getPublishStatus());
                MpAutoMessagePageVO.Message message = new MpAutoMessagePageVO.Message();
                message.setSourceType(mpAutoMessageDO.getSourceType());
                mpAutoMessagePageVO.setMessage(message);
                result.setRecords(Arrays.asList(mpAutoMessagePageVO));
            }
        }
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean add(MpAutoMessageParam param) {
        Long userId = UserUtils.getUserId();
        MpAutoMessageDO mpAutoMessageDO = new MpAutoMessageDO();
        setValue(param, mpAutoMessageDO);
        mpAutoMessageDO.setCreateBy(userId);
        mpAutoMessageDO.setCreateTime(LocalDateTime.now());
        mpAutoMessageDO.setModifyTime(LocalDateTime.now());
        mpAutoMessageMapper.insert(mpAutoMessageDO);
        if (MessageEventEnum.KEY.getEventType().equals(param.getEventType())) {
            mpAutoMessageKeyServiceImpl.modify(mpAutoMessageDO.getId(), mpAutoMessageDO.getAppId(), param.getKeys());
        }
        return true;
    }

    @Override
    public Boolean modify(MpAutoMessageParam param) {
        Long userId = UserUtils.getUserId();
        MpAutoMessageDO mpAutoMessageDO = new MpAutoMessageDO();
        setValue(param, mpAutoMessageDO);
        mpAutoMessageDO.setModifyBy(userId);
        mpAutoMessageDO.setModifyTime(LocalDateTime.now());
        mpAutoMessageMapper.updateById(mpAutoMessageDO);
        if (MessageEventEnum.KEY.getEventType().equals(param.getEventType())) {
            mpAutoMessageKeyServiceImpl.modify(mpAutoMessageDO.getId(), mpAutoMessageDO.getAppId(), param.getKeys());
        }
        return true;
    }

    @Override
    public MpAutoMessageVO view(Long id) {
        MpAutoMessageDO mpAutoMessageDO = mpAutoMessageMapper.selectById(id);
        MpAutoMessageVO mpAutoMessageVO = new MpAutoMessageVO();
        mpAutoMessageVO.setId(mpAutoMessageDO.getId());
        mpAutoMessageVO.setAppId(mpAutoMessageDO.getAppId());
        mpAutoMessageVO.setEventType(mpAutoMessageDO.getAutoType());
        mpAutoMessageVO.setRuleName(mpAutoMessageDO.getName());
        if (MessageEventEnum.KEY.getEventType().equals(mpAutoMessageDO.getAutoType())) {
            List<MpAutoMessageKeyBO> keys = mpAutoMessageKeyServiceImpl.queryByMessageId(id);
            mpAutoMessageVO.setKeys(keys.parallelStream().map(MpAutoMessageKeyBO::getKeyword).collect(Collectors.toList()));
        }
        MpAutoMessageVO.Message message = new MpAutoMessageVO.Message();
        message.setSourceType(mpAutoMessageDO.getSourceType());
        message.setUnionKey(mpAutoMessageDO.getUnionKey());
        if (!WxMpSourceTypeEnum.TEXT.name().equals(mpAutoMessageDO.getSourceType())) {
            WxMpSourceVO view = mpSourceServiceImpl.view(Long.valueOf(mpAutoMessageDO.getUnionKey()));
            if (WxMpSourceTypeEnum.IMAGE_TEXT.name().equals(mpAutoMessageDO.getSourceType())) {
                message.setWxMpSourceDetailPageVos(JsonUtils.jsonToList(view.getSourceDetail(), WxMpSourceDetailPageVO.class));
            } else {
                message.setRepUrl(view.getPath());
                message.setRepName(view.getPath().substring(view.getPath().lastIndexOf("/") + 1));
            }
        }
        mpAutoMessageVO.setMessage(message);
        return mpAutoMessageVO;
    }

    @Override
    public Boolean changeStatus(Long id, Integer status) {
        MpAutoMessageDO query = mpAutoMessageMapper.selectById(id);
        if (!MessageEventEnum.KEY.getEventType().equals(query.getAutoType())) {
            throw new BusinessException("禁止修改非关键字的默认回复状态");
        }
        MpAutoMessageDO mpAutoMessageDO = new MpAutoMessageDO();
        mpAutoMessageDO.setId(id);
        mpAutoMessageDO.setPublishStatus(status);
        mpAutoMessageDO.setModifyTime(LocalDateTime.now());
        return mpAutoMessageMapper.updateById(mpAutoMessageDO) > 0;
    }

    @Override
    public Boolean del(Long id) {
        MpAutoMessageDO query = mpAutoMessageMapper.selectById(id);
        if (!MessageEventEnum.KEY.getEventType().equals(query.getAutoType())) {
            throw new BusinessException("禁止删除非关键字的默认回复");
        }
        mpAutoMessageMapper.deleteById(id);
        mpAutoMessageKeyServiceImpl.deleteByMessageId(id);
        return true;
    }

    @SneakyThrows
    @Override
    public Boolean syncAutoReplayMessageFromWx(Integer type) {
        Long tenantId = UserUtils.getTenantID();
        WxMpService wxMpService = wxOpenServiceImpl.getWxOpenMpService(tenantId);
        if (wxMpService == null) {
            throw new BusinessException("无法获取公众号信息，请检查是否绑定公众号！");
        }
        WxMpConfigStorage WxMpConfigStorage = wxMpService.getWxMpConfigStorage();
        if (WxMpConfigStorage == null) {
            throw new BusinessException("无法获取公众号信息，请检查是否绑定公众号！");
        }
        String appId = WxMpConfigStorage.getAppId();
        LogUtils.info("========appId:{}======",appId);
        if(StringUtils.isEmpty(appId)){
            throw new BusinessException("无法获取公众号APPID，请检查是否绑定公众号！");
        }
        WxMpCurrentAutoReplyInfo WxMpCurrentAutoReplyInfo = wxMpService.getCurrentAutoReplyInfo();
        if (WxMpCurrentAutoReplyInfo == null) {
            throw new BusinessException("无法获取公众号信息，请检查是否绑定公众号！");
        }
        if(type == 1) {
            WxMpCurrentAutoReplyInfo.AutoReplyInfo addFriendAutoReplyInfo = WxMpCurrentAutoReplyInfo.getAddFriendAutoReplyInfo();
            LogUtils.info("========AutoReplyInfo:{}======",JsonUtils.toJsonStr(addFriendAutoReplyInfo));
            LambdaQueryWrapper<MpAutoMessageDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(MpAutoMessageDO::getAutoType, MessageEventEnum.SUBSCRIBE.getEventType());
            mpAutoMessageMapper.delete(queryWrapper);
            if(addFriendAutoReplyInfo != null){
                MpAutoMessageDO mpAutoMessageDO = new MpAutoMessageDO();
                mpAutoMessageDO.setId(IdGenerator.getId());
                mpAutoMessageDO.setAppId(appId);
                mpAutoMessageDO.setName("");
                mpAutoMessageDO.setAutoType(MessageEventEnum.SUBSCRIBE.getEventType());
                mpAutoMessageDO.setSourceType(addFriendAutoReplyInfo.getType().toUpperCase());
                mpAutoMessageDO.setUnionKey(addFriendAutoReplyInfo.getContent());
                mpAutoMessageDO.setPublishStatus(PublishStatusEnum.ENABLE.getValue());
                mpAutoMessageDO.setCreateBy(UserUtils.getUserId());
                mpAutoMessageDO.setCreateTime(LocalDateTime.now());
                mpAutoMessageDO.setModifyTime(LocalDateTime.now());
                mpAutoMessageMapper.insert(mpAutoMessageDO);
            }
        }else if(type == 2) {
            WxMpCurrentAutoReplyInfo.AutoReplyInfo defaultAutoReplyInfo = WxMpCurrentAutoReplyInfo.getMessageDefaultAutoReplyInfo();
            LogUtils.info("========AutoReplyInfo:{}======",JsonUtils.toJsonStr(defaultAutoReplyInfo));
            LambdaQueryWrapper<MpAutoMessageDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(MpAutoMessageDO::getAutoType, MessageEventEnum.NO_KEY.getEventType());
            mpAutoMessageMapper.delete(queryWrapper);
            if(defaultAutoReplyInfo != null){
                MpAutoMessageDO mpAutoMessageDO = new MpAutoMessageDO();
                mpAutoMessageDO.setId(IdGenerator.getId());
                mpAutoMessageDO.setAppId(appId);
                mpAutoMessageDO.setName("");
                mpAutoMessageDO.setAutoType(MessageEventEnum.NO_KEY.getEventType());
                mpAutoMessageDO.setSourceType(defaultAutoReplyInfo.getType().toUpperCase());
                mpAutoMessageDO.setUnionKey(defaultAutoReplyInfo.getContent());
                mpAutoMessageDO.setPublishStatus(PublishStatusEnum.ENABLE.getValue());
                mpAutoMessageDO.setCreateBy(UserUtils.getUserId());
                mpAutoMessageDO.setCreateTime(LocalDateTime.now());
                mpAutoMessageDO.setModifyTime(LocalDateTime.now());
                mpAutoMessageMapper.insert(mpAutoMessageDO);
            }
        }else if(type == 3) {
            WxMpCurrentAutoReplyInfo.KeywordAutoReplyInfo keywordAutoReplyInfo = WxMpCurrentAutoReplyInfo.getKeywordAutoReplyInfo();
            LogUtils.info("========KeywordAutoReplyInfo:{}======",JsonUtils.toJsonStr(keywordAutoReplyInfo));
            LambdaQueryWrapper<MpAutoMessageDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(MpAutoMessageDO::getAutoType, MessageEventEnum.KEY.getEventType());
            mpAutoMessageMapper.delete(queryWrapper);
            if(keywordAutoReplyInfo != null){
                List<WxMpCurrentAutoReplyInfo.AutoReplyRule> autoReplyRules  = keywordAutoReplyInfo.getList();
                if(autoReplyRules.size() >0) {
                    autoReplyRules.stream().forEach(d->{
                        MpAutoMessageDO mpAutoMessageDO = new MpAutoMessageDO();
                        Long uuid = IdGenerator.getId();
                        mpAutoMessageDO.setId(uuid);
                        mpAutoMessageDO.setAppId(appId);
                        mpAutoMessageDO.setName(d.getRuleName());
                        mpAutoMessageDO.setAutoType(MessageEventEnum.KEY.getEventType());
                        mpAutoMessageDO.setSourceType(d.getReplyMode());
                        mpAutoMessageDO.setUnionKey(JsonUtils.toJsonStr(d));
                        mpAutoMessageDO.setPublishStatus(PublishStatusEnum.ENABLE.getValue());
                        mpAutoMessageDO.setCreateBy(UserUtils.getUserId());
                        mpAutoMessageDO.setCreateTime(LocalDateTime.now());
                        mpAutoMessageDO.setModifyTime(LocalDateTime.now());
                        mpAutoMessageMapper.insert(mpAutoMessageDO);
                        MpAutoMessageKeyDO mpAutoMessageKeyDO = new MpAutoMessageKeyDO();
                        mpAutoMessageKeyDO.setId(IdGenerator.getId());
                        mpAutoMessageKeyDO.setAppId(appId);
                        mpAutoMessageKeyDO.setMessageId(uuid);
                        mpAutoMessageKeyDO.setKeyword(JsonUtils.toJsonStr(d.getKeywordListInfo()));
                        mpAutoMessageKeyDO.setReplyInfo(JsonUtils.toJsonStr(d.getReplyListInfo()));
                        mpAutoMessageKeyDO.setAllEquals(0);
                        mpAutoMessageKeyDO.setCreateTime(LocalDateTime.now());
                        mpAutoMessageKeyMapper.insert(mpAutoMessageKeyDO);
                    });
                }
            }
        }
        return true;
    }

    @Override
    public KeyWordBO queryKeyWord(KeyWordQuery query) {
        KeyWordBO result = null;
        //全匹配查询
        List<MpAutoMessageKeyBO> messageIds = mpAutoMessageKeyServiceImpl.queryByKeyWord(query, true);
        if (Collections3.isEmpty(messageIds)) {
            //模糊匹配查询
            messageIds = mpAutoMessageKeyServiceImpl.queryByKeyWord(query, false);
            if (Collections3.isEmpty(messageIds)) {
                return null;
            }
        }
        result = new KeyWordBO();
        if (1 == messageIds.size()) {
            MpAutoMessageDO mpAutoMessageDO = mpAutoMessageMapper.selectById(messageIds.get(0).getMessageId());
            result.setSourceType(mpAutoMessageDO.getSourceType());
            result.setUnionKey(mpAutoMessageDO.getUnionKey());
        } else if (messageIds.size() < 5) {
            List<String> collect = messageIds.stream().map(MpAutoMessageKeyBO::getKeyword).collect(Collectors.toList());
            result.setUnionKey(String.join(",", collect));
        } else {
            List<String> collect = messageIds.subList(0, 5).stream().map(MpAutoMessageKeyBO::getKeyword).collect(Collectors.toList());
            result.setUnionKey(String.join(",", collect));
        }
        //查询回复内容
        return result;
    }

    @Override
    public List<MpAutoMessageBO> queryByCondition(MpAutoMessageDO mpAutoMessageDO) {
        List<MpAutoMessageDO> mpAutoMessageDos = mpAutoMessageMapper.selectList(new LambdaQueryWrapper<>(MpAutoMessageDO.class)
                .eq(MpAutoMessageDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue())
                .eq(MpAutoMessageDO::getAppId, mpAutoMessageDO.getAppId())
                .eq(MpAutoMessageDO::getAutoType, mpAutoMessageDO.getAutoType())
        );
        return JsonUtils.jsonToList(mpAutoMessageDos, MpAutoMessageBO.class);
    }

    private void setValue(MpAutoMessageParam param, MpAutoMessageDO mpAutoMessageDO) {
        mpAutoMessageDO.setId(param.getId());
        mpAutoMessageDO.setAppId(param.getAppId());
        mpAutoMessageDO.setName(param.getRuleName());
        mpAutoMessageDO.setAutoType(param.getEventType());
        mpAutoMessageDO.setSourceType(param.getMessage().getSourceType());
        mpAutoMessageDO.setUnionKey(param.getMessage().getUnionKey());
        mpAutoMessageDO.setRemark(param.getRemark());
        if (MessageEventEnum.KEY.getEventType().equals(mpAutoMessageDO.getSourceType())) {
            if (Collections3.isEmpty(param.getKeys())) {
                throw new BusinessException("关键字必填");
            }
        } else {
            mpAutoMessageDO.setPublishStatus(PublishStatusEnum.ENABLE.getValue());
        }
    }
}
